#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <GL\glut.h>
#include "3rd party lib\trackball.h"
#include "RenderView.h"

using namespace std;
//
//GLOBAL VARIABLE
//
// Trackball object.
TrackBall tb( GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON );
RenderView o_renderView;
double light_pos[] = {10.0, 10.0, 10.0};
////////////////////////////////////
//
// Initialize
//
////////////////////////////////////
void init(int argc, char** argv)
{
	//read input
	o_renderView.ReadDataFromFile("test.off");

	o_renderView.SetNeighborList();
	//simplification
	

    //o_renderView.CalculateUnfoldAngle();
	o_renderView.SetFaceNeighborList();	
	
	//o_renderView.SimplifyMesh();
	//recal unfold angle after simplify
	//o_renderView.CalculateUnfoldAngle();

	//4 lines: Trace line + max min
	o_renderView.CalculateFunctionValue();	
    o_renderView.CalculateLocalMaxMin();
	o_renderView.CalculateLocalSaddle();
    o_renderView.CalculateTraceLine();


	//Build graph for unfolding
	o_renderView.BuildGraph();

	//Add trace list to segment the graph first
	o_renderView.SegmentGraph();

	//Break the graph to be a tree
	o_renderView.BreakGraph();
	//process unfold
	o_renderView.CalculateUnfoldCoord();

    
    
	//Initialize
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 800);
	glutCreateWindow("3D Paper Crafting");

	
	//light position
	GLfloat light_position[] = { light_pos[0],
		light_pos[1],
		light_pos[2],
		1.0 };

	glClearColor (0.0, 0.0, 0.0, 0.0);
	glShadeModel (GL_SMOOTH);

	GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0};
	GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 0.5};

	//glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	//glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	//glLightfv(GL_LIGHT0, GL_POSITION, light_position);

	//glEnable(GL_LIGHTING);
	//glEnable(GL_LIGHT0);

	glEnable(GL_DEPTH_TEST);
}

////////////////////////////////////
//
// The main render function
//
////////////////////////////////////
void draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//view transformation
	gluLookAt(0.0, 5.0, 7.0,
			  0.0, 0.0, 0.0,
			  0.0, 1.0, 0.0);
    
    glPushMatrix();
    {
	    tb.applyTransform();
		//o_renderView.RenderTraceLine();
		o_renderView.RenderOffModel();
	    //o_renderView.RenderUnfoldModel();
        //o_renderView.RenderUnfoldShaderModel();
        //render max min point
        //o_renderView.RenderLocalMaxMin();
		//o_renderView.RenderLocalSaddle();
        
    }
    glPopMatrix();

	glutSwapBuffers();
}

////////////////////////////////////
//
// reshape
//
////////////////////////////////////
void reshape(int w, int h)
{
	tb.reshape( w, h );
	double near = 1.0, far = 100.0;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	//set camera
	glLoadIdentity();
	gluPerspective(45, (double)w / (double) h, near, far);
	glMatrixMode(GL_MODELVIEW);
}
////////////////////////////////////
//
// keyboard function
//
////////////////////////////////////
void keyboard (unsigned char key, int x, int y)
{
	switch (key) 
	{	
	// Quit program.
	case 'q':
	case 'Q': 
		exit(0);
		break;
	}
}
////////////////////////////////////
//
// Special key function
//
////////////////////////////////////
void processSpecialKeys(int key, int x, int y) {

	switch(key) {
		case GLUT_KEY_UP : 
			glutPostRedisplay();
			break;
		case GLUT_KEY_DOWN : 
			glutPostRedisplay();
			break;
		case GLUT_KEY_LEFT : 
			glutPostRedisplay();
			break;
		case GLUT_KEY_RIGHT : 
			glutPostRedisplay();
			break;
	}
}
/////////////////////////////////////////////////////////////////////////////
// The mouse callback function.
/////////////////////////////////////////////////////////////////////////////
static void MyMouse( int button, int state, int x, int y )
{
	tb.mouse( button, state, x, y );
	glutPostRedisplay();
}
/////////////////////////////////////////////////////////////////////////////
// The mouse motion callback function.
/////////////////////////////////////////////////////////////////////////////
static void MyMotion( int x, int y )
{
	tb.motion(x, y);
	glutPostRedisplay();
} 

int main(int argc, char** argv)
{
	cout<<" My FYP Framework"<<endl;
	cout<<" Name: Do Anh Quang"<<endl;
	cout<<" Matric: U087230A"<<endl;
	cout<<"-----------------Command button-----------------"<<endl;
	cout<<" Press Left mouse + Drag to change view"<<endl;
	cout<<" Press Right mouse + Drag to zoom"<<endl;
	cout<<" Press Middle mouse + Drag to pan"<<endl;
	cout<<" Press 'UP/DOWN/LEFT/RIGHT' to move the Triangle."<<endl;
	cout<<" Press 'R' to reset to initial view."<<endl;
	cout<<" Press 'Q' to quit."<<endl;
	init (argc, argv);
	glutDisplayFunc(draw);
	glutIdleFunc(draw);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutMouseFunc( MyMouse );
	glutMotionFunc( MyMotion );
	glutSpecialFunc(processSpecialKeys);
	glutMainLoop();
	return 0;
}